package com.icehand.utils.lock.impl;

import com.icehand.utils.lock.LockService;
import com.icehand.utils.redis.RedisCacheUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;

import java.util.concurrent.TimeUnit;

public class RedisLockServiceImpl implements LockService {

    private final static long TIME_MAX_LOCK = 1000L * 7;

    private final static String NOT_EXIST_VALUE = "nil";

    private final static long SUCCESS_RESULT = 1;

    @Override
    public boolean lock(String source) {
        do {
            if (tryLock(source)) {
                return true;
            }
            try {
                TimeUnit.MILLISECONDS.sleep(300);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        } while (true);
        return false;
    }

    @Override
    public boolean tryLock(String source) {
        String value = System.currentTimeMillis() + TIME_MAX_LOCK + "";
        try{
            Long result = RedisCacheUtils.getJedis().setnx(source, value);
            if (result == SUCCESS_RESULT) {
                return true;
            }
            String oldValue = RedisCacheUtils.getJedis().get(source);
            if (StringUtils.equals(oldValue, NOT_EXIST_VALUE)) {
                result =  RedisCacheUtils.getJedis().setnx(source, value);
                return result == SUCCESS_RESULT;
            }
            long time = NumberUtils.toLong(oldValue);
            if (time < System.currentTimeMillis()) {
                String oldValueMirror = RedisCacheUtils.getJedis().getSet(source, System.currentTimeMillis() + TIME_MAX_LOCK + "");
                return StringUtils.equals(oldValueMirror, NOT_EXIST_VALUE) || StringUtils.equals(oldValue, oldValueMirror);
            }
        }finally {
            RedisCacheUtils.returnJedis();
        }
        return false;
    }

    @Override
    public boolean tryLock(String source, long timeout, TimeUnit unit) {
        return false;
    }

    @Override
    public boolean unlock(String source) {
        try{
            RedisCacheUtils.getJedis().del(source);
        }finally {
            RedisCacheUtils.returnJedis();
        }
        return true;
    }

    public static void main(String[] args) {
        RedisLockServiceImpl redis = new RedisLockServiceImpl();
        System.out.println(redis.tryLock("1234"));
        System.out.println(redis.tryLock("1234"));
    }
}
